using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using Elderos.Utils.Logging;

namespace Elderos.AI
{
    [Serializable]
    [DataContract]
    public class RankNormalizer : INormalizer
    {
        [DataMember]
        public List<double>[] Ranks { get; private set; } 

        public RankNormalizer(double[][] inputs)
        {
            var reversed = new List<double>[inputs.First().Length];
            for (int i = 0; i < reversed.Length; i++)
            {
                reversed[i] = new List<double>();
            }

            foreach (double[] doubles in inputs)
            {
                for (int i = 0; i < doubles.Length; i++)
                {
                    reversed[i].Add(doubles[i]);
                }
            }

            Ranks = new List<double>[reversed.Length];
            
            for (int i = 0; i < reversed.Length; i++)
            {
                Ranks[i] = new List<double>(reversed[i].OrderBy(x => x).Distinct().OrderBy(x => x));
            }
        }


        public double[] Normalize(double[] item)
        {
            if (item.Length != Ranks.Length) throw new ArgumentException();

            var result = new double[item.Length];

            for (int i = 0; i < item.Length; i++)
            {
                int index = Ranks[i].BinarySearch(item[i]);
                double coef;

                //normalized value 0..1
                if (index >= 0)
                {
                    
                    coef = index * 1.0 / (Ranks[i].Count - 1);
                }
                else
                {
                    coef = Math.Max(~index, Ranks[i].Count - 1) * 1.0 / (Ranks[i].Count - 1);
                }
                coef = 2 * coef - 1;
                result[i] = coef;
            }

            return result;
        }
    }
}